/* //device/system/broncho-ril/reference-ril.c
**
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/

#include <telephony/ril.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <alloca.h>
#include "atchannel.h"
#include "at_tok.h"
#include "ril_util.h"
#include <getopt.h>
#include "broncho-ril.h"

#define LOG_TAG "RIL"
#include "broncho_log.h"

static void requestCancelUSSD (RIL* thiz, void *data, size_t datalen, RIL_Token t)
{
	if(ril_command_exec_for_result(thiz, "AT+CUSD=2"))
	{
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, NULL, 0);
    } 
	else 
	{
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
    }
	
	return;
}

static void  requestSendUSSD(RIL* thiz, void *data, size_t datalen, RIL_Token t)
{
    const char *ussdRequest = NULL;
	char* cmd = NULL;

	RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, NULL, 0);

    ussdRequest = (char *)(data);
	asprintf(&cmd, "AT+CUSD=1,\"%s\"", ussdRequest);
	if(!ril_command_exec_full_for_result(thiz, cmd, 25000))
	{
		char* str[1] = {0};

		str[0] = "2";
		RIL_onUnsolicitedResponse(thiz, RIL_UNSOL_ON_USSD, str, sizeof(str));
	}
	free(cmd);

	return;
}

static void requestSetSuppSvcNotification(RIL* thiz, void *data, size_t datalen, RIL_Token t)
{
	int flag = ((int *)data)[0];
	char cmd[32] = {0};

	snprintf(cmd, 32, "AT+CSSN=%d,%d", flag, flag);
	if(ril_command_exec_for_result(thiz, cmd))
	{
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, NULL, 0);
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
	}
	
	return;
}

static void requestQueryClip(RIL* thiz, void *data, size_t datalen, RIL_Token t)
{
	ATResponse* p_resp = NULL;
	int result = 0;
	int ignore = 0;
	int success = 0;

	if(ril_command_exec_singleline_for_result(thiz, "AT+CLIP?", "+CLIP:", &p_resp))
	{
		if(at_line_scanf_int_int(p_resp->p_intermediates->line, &ignore, &result))
		{
			success = 1;
		}
	}

	if(success)
	{
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, &result, sizeof(result));
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
	}
	at_response_free(p_resp);

	return;
}

static void requestChangeBarringPassword(RIL* thiz, void *data, size_t datalen, RIL_Token t)
{
	char* code = ((char**)data)[0];
	char* oldPass = ((char**)data)[1];
	char* newPass= ((char**)data)[2];
	char cmd[64] = {0};

	snprintf(cmd, 64, "AT+CPWD=\"%s\",\"%s\",\"%s\"", code, oldPass, newPass);
	if(ril_command_exec_for_result(thiz, cmd))
	{
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, NULL, 0);
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
	}

	return;
}

static void requestSetFacilityLock(RIL* thiz, void *data, size_t datalen, RIL_Token t)
{
	char* code = ((char**)data)[0];
	char* action = ((char**)data)[1];
	char* password = ((char**)data)[2];
	char* class = ((char**)data)[3];
	char cmd[64] = {0};

	if(class[0] == '0')
	{
		snprintf(cmd, 64, "AT+CLCK=\"%s\",%s,\"%s\",7", code, action, password);
	}
	else
	{
		snprintf(cmd, 64, "AT+CLCK=\"%s\",%s,\"%s\",%s", code, action, password, class);
	}
	if(ril_command_exec_full_for_result(thiz, cmd, 10000))
	{
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, NULL, 0);
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
	}

	return;
}

static void requestQueryFacilityLock(RIL* thiz, void *data, size_t datalen, RIL_Token t)
{
	char* code = ((char**)data)[0];
	char* password = ((char**)data)[1];
	char* class = ((char**)data)[2];
	char cmd[128] = {0};
	int result = 0;
	ATLine *p_cur = NULL;
	int err = 0;
	int status = 0;
	int classNo = 0;
	int i = 0;
	ATResponse* p_resp = NULL;

	class = (class[0] == '0') ? "7" : class;
	//snprintf(cmd, 128, "AT+CLCK=\"%s\",2,\"%s\",%s", code, password, class);
	snprintf(cmd, 128, "AT+CLCK=\"%s\",2", code);
	err = ril_send_command_multiline(thiz, cmd, "+CLCK:", &p_resp);

	if (err == 0 && p_resp->success == 1)
	{
		for (i = 0, p_cur = p_resp->p_intermediates; p_cur != NULL; p_cur = p_cur->p_next, i++ )
		{
			char *line = p_cur->line;
			err = at_tok_start(&line);
			if (err < 0) break;

			err = at_tok_nextint(&line, &status);
			if (err < 0) break;

			if (!at_tok_hasmore(&line))
			{
				if(status == 1)
					result += 7;
				continue;
			}

			err = at_tok_nextint(&line, &classNo);
			if (err < 0) break;
			if(status == 1)
				result += classNo;
		}
	}

	if(err == 0 && p_resp->success == 1)
	{
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS,&result , sizeof(result));
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
	}
	at_response_free(p_resp);

	return;
}

static void requestSetCallWaiting(RIL* thiz, void *data, size_t datalen, RIL_Token t)
{
	int action = ((int *)data)[0];
	int class = ((int *)data)[1];
	char cmd[32] = {0};

	class = (class == 0) ? 7 : class;
	snprintf(cmd, 32, "AT+CCWA=1,%d,%d", action, class);
	if(ril_command_exec_full_for_result(thiz, cmd, 20000))
	{
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, NULL, 0);
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
	}

	return;
}

static void requestQueryCallWaiting(RIL* thiz, void *data, size_t datalen, RIL_Token t)
{
	ATResponse* p_resp = NULL;
	int class = ((int *)data)[0];
	char cmd[32] = {0};
	int err = 0;
	ATLine *p_cur = NULL;
	int result[2] = {0};
	int enable = 0;
	int i = 0;

	class = (class == 0) ? 7 : class;
	snprintf(cmd, 32, "AT+CCWA=1,2,%d", class);
	err = ril_send_command_multiline_full(thiz, cmd, 20000, "+CCWA:", &p_resp);
	if(err == 0 && p_resp->success == 1)
	{
		for (i = 0, p_cur = p_resp->p_intermediates; p_cur != NULL; p_cur = p_cur->p_next, i++ )
		{
			char *line = p_cur->line;

			err = at_tok_start(&line);
			if (err < 0) break;

			err = at_tok_nextint(&line, &enable);
			if (err < 0) break;

			err = at_tok_nextint(&line, &class);
			if (err < 0) break;
			if(enable == 1)
			{
				result[1] += class;
			}
		}
	}
	result[0] = (result[1] > 0) ? 1 : 0;

	if(err < 0)
	{
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, result, sizeof(result));
	}
	at_response_free(p_resp);

	return;
}

static void requestSetCallForward(RIL* thiz, void *data, size_t datalen, RIL_Token t)
{
	char cmd[129] = {0};
	RIL_CallForwardInfo * info = (RIL_CallForwardInfo *)data;

	info->serviceClass = (info->serviceClass == 0) ? 7 : info->serviceClass;

	if(info->status == 3 && info->reason == 2)
	{
		snprintf(cmd, 128, "AT+CCFC=%d,3,\"%s\",%d,%d,,,%d", 
				info->reason, info->number, info->toa, info->serviceClass, info->timeSeconds);
	}
	else
	{
		snprintf(cmd, 128, "AT+CCFC=%d,%d,\"%s\",%d,%d", 
				info->reason, info->status, info->number, info->toa, info->serviceClass);
	}
	if(ril_command_exec_full_for_result(thiz, cmd, 20000))
	{
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, NULL, 0);
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
	}

	return;
}

static void requestQueryCallForwardStatus(RIL* thiz, void *data, size_t datalen, RIL_Token t)
{
	ATResponse* p_resp = NULL;
	RIL_CallForwardInfo * info = (RIL_CallForwardInfo *)data;
	char cmd[64] = {0};
	int err = 0;
	ATLine *p_cur;
	RIL_CallForwardInfo** result;
	int number = 0;
	int i = 0;

	snprintf(cmd, 64, "AT+CCFC=%d,2",info->reason);
	err = ril_send_command_multiline_full(thiz, cmd, 20000, "+CCFC:", &p_resp);
	if (err != 0 || p_resp->success == 0) 
	{
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
		return;
	}

	for (p_cur = p_resp->p_intermediates; p_cur != NULL; p_cur = p_cur->p_next)  number++;
	result = alloca(number*sizeof(RIL_CallForwardInfo*));
	i = 0; 
	while(i < number) 
	{
		result[i] = alloca(sizeof(RIL_CallForwardInfo));
		i++;
	}

	i = 0; 
	for (p_cur = p_resp->p_intermediates; p_cur != NULL; p_cur = p_cur->p_next)
	{
		char *line = p_cur->line;
		char* ignore;
		int ignoreSubtype;
		result[i]->status = 0;
		result[i]->reason = 0;
		result[i]->serviceClass = 0;
		result[i]->toa = 0;
		result[i]->number = NULL;
		result[i]->timeSeconds = 0;

		err = at_tok_start(&line);
		if (err < 0) break;

		err = at_tok_nextint(&line, &(result[i]->status));
		if (err < 0) break;
		ALOGD("CCFC: status:%d",result[i]->status);

		err = at_tok_nextint(&line, &(result[i]->serviceClass));
		if (err < 0) break;
		ALOGD("CCFC: serviceClass:%d",result[i]->serviceClass);
		if (!at_tok_hasmore(&line))  continue;

		err = at_tok_nextstr(&line, &(result[i]->number));
		ALOGI("CCFC: number:%s",result[i]->number);
		if (err < 0) break;
		if (!at_tok_hasmore(&line))  continue;

		err = at_tok_nextint(&line, &(result[i]->toa));
		ALOGI("CCFC: type:%d",result[i]->toa);
		if (err < 0) break;
		if (!at_tok_hasmore(&line))  continue;

		err = at_tok_nextstr(&line, &ignore);
		if (err < 0) break;
		if (!at_tok_hasmore(&line))  continue;

		err = at_tok_nextint(&line, &ignoreSubtype);
		if (err < 0) break;
		if (!at_tok_hasmore(&line))  continue;

		err = at_tok_nextint(&line, &(result[i]->timeSeconds));
		if (err < 0) break;
		ALOGD("CCFC: type:%d",result[i]->timeSeconds);

		i++;
	}

	if(err < 0)
	{
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, result, sizeof(number*sizeof(RIL_CallForwardInfo*)));
	}
	at_response_free(p_resp);
	return;
}

static void requestSetClir(RIL* thiz, void *data, size_t datalen, RIL_Token t)
{
	char cmd[32] = {0};
	int mode = ((int*)data)[0];

	snprintf(cmd, 31, "AT+CLIR=%d", mode);
	if(ril_command_exec_full_for_result(thiz, cmd, 20000))
	{
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, NULL, 0);
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
	}
}

static void requestGetClir(RIL* thiz, void *data, size_t datalen, RIL_Token t)
{
	ATResponse* p_resp = NULL;
	int success = 0;
	int result[2] = {0};

	if(ril_command_exec_singleline_for_result(thiz, "AT+CLIR?", "+CLIR:", &p_resp))
	{
		if(at_line_scanf_int_int(p_resp->p_intermediates->line, &result[0], &result[1]))
		{
			success = 1;
		}
		at_response_free(p_resp);
	}

	if(success)
	{
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, result, sizeof(result));
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
	}

	return;
}

static void onUnsolicited_Cssi(RIL* thiz, const char* s)
{
	char* line = NULL;
	char* dump_str = NULL;
	int err = 0;
	RIL_SuppSvcNotification resp;

	dump_str = strdup(s);
	line = dump_str;
	
	ALOGD("onUnsolicited_Cssi 1");
	memset(&resp, 0, sizeof(RIL_SuppSvcNotification));
	resp.notificationType = 0;

	ALOGD("onUnsolicited_Cssi 2");
	do
	{
		if ((err = at_tok_start(&line)) < 0)
		{
			break;
		}
		
		ALOGD("onUnsolicited_Cssi 3");
		if((err = at_tok_nextint (&line, &resp.code)) < 0)
		{
			break;
		}
		
		ALOGD("onUnsolicited_Cssi 3");
		if(at_tok_hasmore(&line))
		{
			if((err = at_tok_nextint (&line, &resp.index)) < 0)
			{
				break;
			}
		}
		
		ALOGD("onUnsolicited_Cssi 4");
		RIL_onUnsolicitedResponse(thiz, RIL_UNSOL_SUPP_SVC_NOTIFICATION,
			&resp, sizeof(RIL_SuppSvcNotification));
	}while(0);
	ALOGD("onUnsolicited_Cssi 5");
	free(dump_str);

	return;
}

static void onUnsolicited_Cssu(RIL* thiz, const char* s)
{
	char* line = NULL;
	char* dump_str = NULL;
	int err = 0;
	RIL_SuppSvcNotification resp;

	dump_str = strdup(s);
	line = dump_str;
	
	memset(&resp, 0, sizeof(RIL_SuppSvcNotification));
	resp.notificationType = 1;
	do
	{
		if ((err = at_tok_start(&line)) < 0)
		{
			break;
		}

		if((err = at_tok_nextint (&line, &resp.code)) < 0)
		{
			break;
		}
		
		if(at_tok_hasmore(&line))
		{
			if((err = at_tok_nextint (&line, &resp.index)) < 0)
			{
				break;
			}
		}

		if(at_tok_hasmore(&line))
		{
			if((err = at_tok_nextstr(&line, &resp.number)) < 0)
			{
				break;
			}
		}

		if(at_tok_hasmore(&line))
		{
			if((err = at_tok_nextint (&line, &resp.type)) < 0)
			{
				break;
			}
		}

		RIL_onUnsolicitedResponse(thiz, RIL_UNSOL_SUPP_SVC_NOTIFICATION,
			&resp, sizeof(RIL_SuppSvcNotification));
	}while(0);
	free(dump_str);

	return;
}

static void onUnsolicited_Cusd(RIL* thiz, const char* s)
{
	char* line = NULL;
	char* dump_str = NULL;
	int err = 0;

	dump_str = strdup(s);
	line = dump_str;
	do
	{
		int type = 0;
		char* str[2] = {0};

		err = at_tok_start(&line);
		if (err < 0) break;

		err = at_tok_nextstr(&line, &str[0]);
		if (err < 0) break;

		if(at_tok_hasmore(&line)) {
			err = at_tok_nextstr(&line, &str[1]);
			if (err < 0) break;
		}

		RIL_onUnsolicitedResponse(thiz, RIL_UNSOL_ON_USSD, str, sizeof(str));
	}while(0);
	free(dump_str);

	return;
}

int RIL_initialize_ss (RIL* thiz)
{
	return 1;
}

int RIL_onUnsolicited_ss (RIL* thiz, const char* s)
{
	int ret = 0;

	if(strStartsWith(s, "+CUSD:"))
	{
		onUnsolicited_Cusd(thiz, s);
		ret = 1;
	} 
	else if(strStartsWith(s, "+CSSI:"))
	{
		onUnsolicited_Cssi(thiz, s);
		ret = 1;
	}
	else if(strStartsWith(s, "+CSSU:"))
	{
		onUnsolicited_Cssu(thiz, s);
		ret = 1;
	}
	

	return ret;
}

int RIL_onRequest_ss (RIL* thiz, int request, void *data, size_t datalen, RIL_Token t)
{
	switch (request)
	{
	case RIL_REQUEST_QUERY_FACILITY_LOCK:
		requestQueryFacilityLock(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_SET_FACILITY_LOCK:
		requestSetFacilityLock(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_CHANGE_BARRING_PASSWORD:
		requestChangeBarringPassword(thiz, data, datalen, t);
		break;
	
	/*
	case RIL_REQUEST_SEND_USSD:
		requestSendUSSD(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_CANCEL_USSD:
		requestCancelUSSD(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_GET_CLIR:
		requestGetClir(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_SET_CLIR:
		requestSetClir(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_QUERY_CALL_FORWARD_STATUS:
		requestQueryCallForwardStatus(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_SET_CALL_FORWARD:
		requestSetCallForward(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_QUERY_CALL_WAITING:
		requestQueryCallWaiting(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_SET_CALL_WAITING:
		requestSetCallWaiting(thiz, data, datalen, t);
		break;

	
	case RIL_REQUEST_QUERY_CLIP:
		requestQueryClip(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION:
		requestSetSuppSvcNotification(thiz, data, datalen, t);
		break;
	*/

	default:
		RIL_onRequestComplete(thiz, t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
		break;
	}

	return 1;
}

